#include <GA\GA.hpp>
#include <GA\operations\fitness\ElemFit.hpp>
#include <GA\operations\selection\RankSlector.hpp>
#include <GA\operations\crossing\OnePointCrosser.hpp>
#include <ctime>
#include <vector>
#include <algorithm>


unitraf::GA::GA( size_t populationSize, TaskFactory* taskFactory, Task * task )
	: _populationSize ( populationSize ), _mutator( MUTATION_PROB ), fit( _populationSize ), _task( task )
{
	srand( (unsigned)time(0) ); 

	_taskFactory = taskFactory;

	//_task = _taskFactory->createTask( ); // in constructor parameter instead

	//create first population
	_population = new BinaryString* [populationSize];

	for ( size_t i = 0; i < _populationSize; ++i )
	{
		_population[i] = taskFactory->createBinStr( );

		for ( size_t j = 0; j < _population[i]->getLength( ); ++j )
		{
			_population[i]->setBit( j, (rand( ) % 2) != 0 );
		}

		_task->makeValid( _population[i] );
	}

	_elitSize = ELIT_SIZE;

	_selector = new RankSlector( );
	_crosser = new OnePointCrosser( );
}

unitraf::GA::~GA( )
{
	for ( size_t i = 0; i < _populationSize; ++i )
	{
		delete _population[i];
	}

	delete [] _population;

	delete _selector;
}



void unitraf::GA::nextGen( )
{
//calculatig fitness

	//store number and fitness of the element
	
	for ( size_t i = 0; i < _populationSize; ++i )
	{
		fit[i]._N = i;
		fit[i]._fitness = _task->fitness( _population[i] );
	}

	std::sort( fit.begin( ), fit.end( ) );

	BinaryString **matingPool = new BinaryString* [ _populationSize ];
	_selector->setFitArray( &fit );


	size_t N;

	//copy best solutions to next gen
	for ( size_t i = 0; i < _elitSize; ++i )
	{
		N = fit[ i ]._N; //find position in population
		matingPool[i] = _population[N]->clone( ); //copy to mating pool
	}
	
	size_t rank;
	//copy selected solutions to next gen
	for ( size_t i = _elitSize; i < _populationSize; ++i )
	{
		rank = _selector->select( ); //select position in sorted fit list
		N = fit[ rank ]._N; //find position in population
		matingPool[i] = _population[N]->clone( ); //copy to mating pool
	}

//crossing
	//fit.size( ) % 2 added in case of not even size
	for ( size_t i = _elitSize; i < _populationSize - _populationSize % 2; i=i+2 )
	{
		_crosser->cross( matingPool[i], matingPool[i+1] );
	}


//mutation
	for ( size_t i = _elitSize; i < _populationSize; ++i )
	{
		_mutator.mutate( matingPool[i] );
	}

	for ( size_t i = 0; i < _populationSize; ++i )
	{
		_task->makeValid( matingPool[i] );
	}

	//delete current population
	for ( size_t i = 0; i < _populationSize; ++i )
	{
		delete _population[i];
	}

	delete [] _population;

	//swap( _population, matingPool)
	_population = matingPool;
	matingPool = 0;
}


unitraf::BinaryString* unitraf::GA::best( ) const
{
	return _population[0];
}
